# -*- coding:utf-8 -*-
# @FileName :Send_Api.py
# @user chunxiangjie
# @Time :2022/8/3 16:18
# -*- coding:utf-8 -*-
# @FileName :Send_Api.py
# @user chunxiangjie
# @Time :2022/8/3 16:18
import json
# Create your views here.
import logging
import re

import pymysql
import requests
from faker import Faker

from api_App.models import *

fake = Faker(locale='zh_CN')
logger = logging.getLogger('django')


def get_MIME(file_name):  # 多用途互联网邮件扩展类型
    d = {
        'image/png': ['png'],
        'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': ['xlsx'],
        'application/vnd.openxmlformats-officedocument.presentationml.presentation': ['pptx'],
        'application/pdf': ['pdf'],
        'image/jpeg': ['jpg', 'jpeg'],
        'application/zip': ['zip'],
        'text/plain': ['txt'],
        'video/mp4': ['mp4'],
        'application/msword': ['doc', 'dot'],
        'application/vnd.openxmlformats-officedocument.wordprocessingml.document': ['docx'],
        'application/vnd.openxmlformats-officedocument.wordprocessingml.template': ['dotx'],
        'application/vnd.ms-word.document.macroEnabled.12': ['docm'],
        'application/vnd.ms-word.template.macroEnabled.12': ['dotm'],
        'application/vnd.ms-excel': ['xls', 'xlt', 'xla'],
        'application/vnd.openxmlformats-officedocument.spreadsheetml.template': ['xltx'],
        'application/vnd.ms-excel.sheet.macroEnabled.12': ['xlsm'],
        'application/vnd.ms-excel.template.macroEnabled.12': ['xltm'],
        'application/vnd.ms-excel.addin.macroEnabled.12': ['xlam'],
        'application/vnd.ms-excel.sheet.binary.macroEnabled.12': ['xlsb'],
        'application/vnd.ms-powerpoint': ['ppt', 'pot', 'pps', 'ppa'],
        'application/vnd.openxmlformats-officedocument.presentationml.slideshow': ['ppsx'],
        'application/vnd.ms-powerpoint.addin.macroEnabled.12': ['ppam'],
        'application/vnd.ms-powerpoint.presentation.macroEnabled.12': ['pptm', 'potm'],
        'application/vnd.ms-powerpoint.slideshow.macroEnabled.12': ['ppsm'],
        'application/x-tar': ['tar'],
    }
    hz = file_name.split('.')[-1]
    for key, value in d.items():
        if hz in value:
            return key
    return 'application/octet-stream'  # 一切未知类型


def make_sign():
    ...
    return ''


class Send_Api:
    def __init__(self, api, TQ, chaildren):
        self.url = None
        self.chaildren = chaildren
        self.api = api
        self.make_Headers()
        self.make_Method()
        self.TQ = TQ
        self.send_real = True
        self.api['payload_method'] = self.api['payload_method'].lower()
        self.api['payload_raw_method'] = self.api['payload_raw_method'].lower()
        self.REPORT = {'label': self.api['label'], 'result': True, 'method': self.api['method']}
        # self.REPORT['headers']={}
        # for i in self.api['headers']:
        #         self.REPORT['headers'][i['key']]=i['value']
        # self.REPORT['response_headers']=self.api['response_headers']

    def TQ_replace(self):
        print('-------------')
        # headers {}
        for key in self.headers.keys():
            tqs = re.findall(r'{%(.*?)%}', self.headers[key])
            for tq in tqs:
                self.headers[key] = self.headers[key].replace('{%' + tq + '%}', str(self.TQ[tq]))
        # params  [{key:'',value:''},{}]
        for i in range(len(self.api['params'])):
            tqs = re.findall(r'{%(.*?)%}', self.api['params'][i]['value'])
            for tq in tqs:
                self.api['params'][i]['value'] = self.api['params'][i]['value'].replace('{%' + tq + '%}',
                                                                                        str(self.TQ[tq]))
        # payload_fd
        for i in range(len(self.api['payload_fd'])):
            tqs = re.findall(r'{%(.*?)%}', self.api['payload_fd'][i]['value'])
            for tq in tqs:
                self.api['payload_fd'][i]['value'] = self.api['payload_fd'][i]['value'].replace('{%' + tq + '%}',
                                                                                                str(self.TQ[tq]))
        # payload_xwfu
        for i in range(len(self.api['payload_xwfu'])):
            tqs = re.findall(r'{%(.*?)%}', self.api['payload_xwfu'][i]['value'])
            for tq in tqs:
                self.api['payload_xwfu'][i]['value'] = self.api['payload_xwfu'][i]['value'].replace('{%' + tq + '%}',
                                                                                                    str(self.TQ[tq]))
        # payload_raw
        tqs = re.findall(r'{%(.*?)%}', self.api['payload_raw'])
        for tq in tqs:
            self.api['payload_raw'] = self.api['payload_raw'].replace('{%' + tq + '%}', str(self.TQ[tq]))
        # payload_GQL_q
        tqs = re.findall(r'{%(.*?)%}', self.api['payload_GQL_q'])
        for tq in tqs:
            self.api['payload_GQL_q'] = self.api['payload_GQL_q'].replace('{%' + tq + '%}', str(self.TQ[tq]))
        # payload_GQL_g
        tqs = re.findall(r'{%(.*?)%}', self.api['payload_GQL_g'])
        for tq in tqs:
            self.api['payload_GQL_g'] = self.api['payload_GQL_g'].replace('{%' + tq + '%}', str(self.TQ[tq]))

    def get_sql(self, sql):
        global cursor, res
        pro_ject_id = self.api['project_id']
        pro_ject = DB_project_list.objects.get(id=int(pro_ject_id))
        Sql_host = pro_ject.Sql_host
        Sql_port = pro_ject.Sql_port
        Sql_user = pro_ject.Sql_user
        Sql_pwd = pro_ject.Sql_pwd
        Sql_name = pro_ject.Sql_name
        try:
            connet = pymysql.Connect(host=Sql_host, port=int(Sql_port), user=Sql_user, password=Sql_pwd,
                                     database=Sql_name, charset='utf8')
            cursor = connet.cursor()
            cursor.execute(sql)
            cursor.connect()
            res = cursor.fetchall()
        except:
            res = ()
        finally:
            try:
                cursor.close()
            except:
                pass

        return res

    def make_Url(self):
        """整理拼接host"""
        host = self.api['host']
        path = self.api['path']
        params = self.api['params']
        self.url = host + path + '?' + '&'.join(['%s=%s' % (i['key'], i['value']) for i in params])
        print(self.url)
        self.REPORT['url'] = self.url

    def make_Headers(self):
        '''整理拼接请求头'''
        self.headers = {}
        for i in self.api['headers']:
            if i['key']:
                self.headers[i['key']] = i['value']

    def make_Method(self):
        self.method = self.api['method'].upper()

    def make_RD(self):
        '''生成返回头数据'''
        self.RD = ''
        self.RD += f'【status_code】:{self.response.status_code}'
        self.RD += str(f'\n【headers】:\n{self.response.headers}')
        logging.info('当前请求头数据为')
        self.REPORT['status_code'] = self.response.status_code
        self.REPORT['response_headers'] = str(self.response.headers)
        if int(self.REPORT['status_code']) > 400:
            self.REPORT['result'] = False

    def send_Confinure(self, configure):
        '执行配置函数'
        '执行配置函数'
        if configure['method'] == '断言':
            if configure['select'] == '全值检索':
                if configure['value'] in self.R:
                    return True
            elif configure['select'] == '正则匹配':
                left = configure['value'].split('==')[0].strip()
                right = configure['value'].split('==')[1].strip()
                if re.findall(left, self.R) == [right]:
                    return True
            elif configure['select'] == '路径匹配':
                left = configure['value'].split('==')[0].strip()
                right = configure['value'].split('==')[1].strip()
                try:
                    if eval(self.R + left) == eval(right):
                        return True
                except:
                    pass
            elif configure['select'] == 'sql断言':
                left = configure['value'].split(';')[0].strip() + ';'
                rigth = configure['value'].split(';')[-1].split('==')[-1].strip()  # right没有进行eval求值
                res = self.get_sql(left)
                if rigth:  # 第一种
                    rigth = eval(rigth)
                    try:
                        if res[0][0] == rigth:
                            return True
                    except:
                        self.REPORT['result'] = False
                        return False
                else:  # 第二种
                    if res:
                        return True
                return True
        elif configure['method'] == '提取':
            if configure['select'] == '路径提取':
                left = configure['value'].split('=')[0].strip()
                right = configure['value'].split('=')[1].strip()
                try:
                    S = locals()
                    exec('s=json.loads(self.R)' + right)
                    self.TQ[left] = S['s']
                    return True
                except:
                    self.REPORT['result'] = False
                    return False
            elif configure['select'] == '正则提取':
                left = configure['value'].split('=')[0].strip()
                right = configure['value'].split('=')[1].strip()
                try:
                    self.TQ[left] = re.findall(right, self.R)[0]
                    return True
                except:
                    self.REPORT['result'] = False
                    return False
            elif configure['select'] == 'sql提取':
                left = configure['value'].split('=')[0].strip()
                right = '='.join(configure['value'].split('=')[1:]).strip()
                res = self.get_sql(right)
                if res:
                    self.TQ[left] = res[0][0]
                    return True
                return True
        elif configure['method'] == 'sql增删改':
            self.get_sql(configure['value'])
            return True
        elif configure['method'] == '随机变量':
            left = configure['value'].split('=')[0].strip()
            right = configure['value'].split('=')[1].strip()
            self.TQ[left] = eval(right)
            return True
        elif configure['method'] == 'mock':
            if configure['select'] == '写死返回值':
                self.R = configure['value']
                self.send_real = False
            elif configure['select'] == '第三方接口':  # 不运行接口，只修改请求数据
                self.url = configure['value'].split('\n')[0]
                self.method = configure['value'].split('\n')[1].upper()
                self.headers = json.loads(configure['value'].split('\n')[2])
                if 'raw' in configure['value'].split('\n')[3]:
                    self.api['payload_method'] = 'raw'
                    self.api['payload_raw_method'] = configure['value'].split('\n')[3].spilt('-')[1]
                else:
                    self.api['payload_method'] = configure['value'].split('\n')[3]
                self.api['payload_fd'] = configure['value'].split('\n')[4]
                self.api['payload_xwfu'] = configure['value'].split('\n')[4]
                self.api['payload_raw'] = configure['value'].split('\n')[4]
            return True
        elif configure['method'] == '插入参数':
            left = configure['value'].split('=')[0].strip()
            print(configure['value'])

            right = eval('='.join(configure['value'].split('=')[1:]).strip())
            if configure['select'] == 'request_header':
                self.headers[left] = right
            elif configure['select'] == 'params':
                self.url += '&' + left + '=' + str(right)
            elif configure['select'] == 'request_body':
                if self.api['payload_method'] == 'form-data'.lower():  # [{"key":"","value","des":""},{}]
                    self.api['payload_fd'].append({"key": left, "value": right})
                elif self.api['payload_method'] == 'x-www-form-urlencoded':
                    self.api['payload_xwfu'].append({"key": left, "value": right})
                elif self.api['payload_method'] == 'raw'.lower() and self.api['payload_raw_method'] == 'json'.lower():
                    s = self.api['payload_raw']
                    s = json.loads(s)
                    s[left] = right
                    self.api['payload_raw'] = json.dumps(s)
            return True
        elif configure['method'] == '加密算法':
            left = configure['value'].split('=')[0].strip()
            right = eval('='.join(configure['value'].split('=')[1:]).strip())
            if configure['select'] == 'request_header':
                self.headers[left] = right
            elif configure['select'] == 'params':
                self.url += '&' + left + '=' + str(right)
            return True
        self.REPORT['result'] = False
        return configure['select'] + configure['value'] + ' ' + '[值错误]'

    def Send_Api(self):
        '''执行接口本体'''
        if self.api['payload_method'] == 'none'.lower():
            self.response = requests.request(self.method, self.url, headers=self.headers, data={})
        elif self.api['payload_method'] == 'form-data'.lower():  # {"a":1,"b":2,"c":3}
            files = []
            payload = {}
            for i in self.api['payload_fd']:
                if '*FILE*' in i['value']:
                    file_name = i['value'].split('*FILE*')[1]
                    files.append(
                        (i['key'], (file_name, open('api_App/static/tmp/' + file_name, 'rb'), get_MIME(file_name))))
                else:
                    payload[i['key']] = i['value']
            self.response = requests.request(self.method, self.url, headers=self.headers, data=payload, files=files)
        elif self.api['payload_method'] == 'x-www-form-urlencoded'.lower():  # 'a=1&b=2&c=3&'
            payload = ''
            for i in self.api['payload_xwfu']:
                payload += '%s=%s&' % (i['key'], i['value'])
            self.headers['Content-Type'] = 'application/x-www-form-urlencoded'
            self.response = requests.request(self.method, self.url, headers=self.headers, data=payload)
        elif self.api['payload_method'] == 'raw.lower()':
            if self.api['payload_raw_method'] == 'Text'.lower():
                self.headers['Content-Type'] = 'text/plain'
            elif self.api['payload_raw_method'] == 'JavaScript'.lower():
                self.headers['Content-Type'] = 'application/javascript'
            elif self.api['payload_raw_method'] == 'JSON'.lower():
                self.headers['Content-Type'] = 'application/json'
            elif self.api['payload_raw_method'] == 'XML'.lower():
                self.headers['Content-Type'] = 'application/xml'
            elif self.api['payload_raw_method'] == 'HTML'.lower():
                self.headers['Content-Type'] = 'text/html'
            self.response = requests.request(self.method, self.url, headers=self.headers, data=self.api['payload_raw'])
        elif self.api['payload_method'] == 'binary'.lower():
            file_name = self.api['binary_file']
            payload = open('api_App/static/tmp/' + file_name, 'rb')
            self.headers['Content-Type'] = ''  # 文件格式
            self.response = requests.request(self.method, self.url, headers=self.headers, data=payload)
        elif self.api['payload_method'] == 'GraphQL'.lower():
            self.headers['Content-Type'] = 'application/json'
            payload = json.dumps({"query": self.api['payload_GQL_q'], "variables": eval(self.api['payload_GQL_g'])})
            self.response = requests.request(self.method, self.url, headers=self.headers, data=payload)
        else:
            self.response = requests.request(self.method, self.url, headers=self.headers)
        try:
            self.R = json.dumps(self.response.json(), ensure_ascii=False)
        except:
            self.R = self.response.text

    def index(self):
        ''' 入口主函数 '''
        try:
            self.TQ_replace()
        except Exception as e:
            self.REPORT['result'] = False
            return {"R": '执行失败：存在未定义变量', "RD": '', "CR": '', "TQ": self.TQ, "REPORT": self.REPORT}
        self.make_Url()
        self.CR = []
        for i in self.chaildren:
            if i['do_time'] == 'before':
                self.CR.append('【%s】%s' % (i['label'], self.send_Confinure(i)))
                self.chaildren.remove(i)
        if self.send_real == True:
            try:
                self.Send_Api()
            except Exception as e:
                self.REPORT['result'] = False
                return {"R": '执行失败：接口请求失败', "RD": '', "CR": '', "TQ": self.TQ, "REPORT": self.REPORT}
        for i in self.chaildren:
            self.CR.append('【%s】%s' % (i['label'], self.send_Confinure(i)))
        self.make_RD()
        self.CR = '\n'.join(self.CR)
        return self.Response_data()

    def Response_data(self):
        '''获取返回结果'''
        self.REPORT['R'] = self.R
        self.REPORT['CR'] = self.CR
        self.REPORT['TQ'] = self.TQ
        self.REPORT['payload_method'] = self.api['payload_method']
        # self.REPORT['url'] = self.url
        self.REPORT['request_headers'] = self.headers
        # self.REPORT['payload_method'] = self.api['payload_method']
        # self.REPORT['payload_raw_method'] = self.api['payload_raw_method']
        self.REPORT['payload'] = json.dumps({
            "payload_fd": self.api['payload_fd'],
            "payload_xwfu": self.api['payload_xwfu'],
            "payload_raw": self.api['payload_raw'],
            "payload_GQL_q": self.api['payload_GQL_q'],
            "payload_GQL_g": self.api['payload_GQL_g'],
        })
        self.REPORT['url'] = self.url

        r = {'R': self.R, 'RD': self.RD, 'CR': self.CR, "TQ": self.TQ, "REPORT": self.REPORT}
        print(self.headers)
        self.REPORT['response_headers'] = self.RD
        return r
